﻿using System;
using Microsoft.Practices.Unity;
using ReactiveGraph.Core;
using ReactiveGraph.Core.Configuration.Containers;
using Unity.AutoRegistration;

namespace ReactiveGraph.Object.Configuration.Containers
{
    public class UnityObjectExtension : UnityContainerExtension
    {

        protected override void Initialize()
        {
            Container.AddExtension(new UnityCoreExtension());
            Container.RegisterType<Func<string, Type, IProperty>>(
                new ContainerControlledLifetimeManager(),
                new InjectionFactory(c =>
                                     new Func<string, Type, IProperty>(
                                         (name, propertyType) => GetProperty(propertyType, name)))
                );

            Container.RegisterType<Func<string, Type, IReactiveNode>>(
                new ContainerControlledLifetimeManager(),
                new InjectionFactory(c =>
                                     new Func<string, Type, IReactiveNode>(
                                         (name, type) => GetNode(type, name)))
                );

            Container.RegisterType<Func<Type, IReactiveNode>>(
                new ContainerControlledLifetimeManager(),
                new InjectionFactory(c =>
                                     new Func<Type, IReactiveNode>(
                                         type => (IReactiveNode) Container.Resolve(type)))
                );
            Container.RegisterType<NodeFactories>(new ContainerControlledLifetimeManager());
            Container.RegisterType<Context>();
            Container
                .ConfigureAutoRegistration()
                .ExcludeSystemAssemblies()
                .Include(If.Implements<IReactiveObject>,
                         (t, c) => c.RegisterType(t, 
                             new InjectionMethod("SetContext", c.Resolve<Context>()),
                             new InjectionMethod("Initialize")))
                .ApplyAutoRegistration();
        }

        private IReactiveNode GetNode(Type t, string name)
        {
            using (var child = Container.CreateChildContainer())
            {
                child.RegisterType<Func<IReactiveNode, string>>(
                    new ContainerControlledLifetimeManager(),
                    new InjectionFactory(c => new Func<IReactiveNode, string>(node => name))
                    );
                return child.Resolve(t) as IReactiveNode;
            }
        }


        private IProperty GetProperty(Type propertyType, string name)
        {
            using (var child = Container.CreateChildContainer())
            {
                child.RegisterInstance(name);
                try
                {
                    return child.Resolve(propertyType) as IProperty;
                }
                catch (Exception)
                {
                    Console.WriteLine("Could not resolve property " + propertyType + " with name " + name);
                    return null;
                }
            }
        }


    }
}
